﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows;
using System.Windows.Input;

namespace SilverTile.Keybard
{
    public class KeyboardHandler : IKeyboardHandler
    {

        private UIElement _uiElement;
        private List<IKeyState> _keyStates;

        private List<Key> _pressedKeys;

        public KeyboardHandler(UIElement uiElement)
        {
            UIElement = uiElement;

            _keyStates = new List<IKeyState>();
            _pressedKeys = new List<Key>();

        }

        public UIElement UIElement
        {
            get { return _uiElement; }
            set
            {
                if (_uiElement != null)
                {
                    _uiElement.KeyDown -= _uiElement_KeyDown;
                    _uiElement.KeyUp -= _uiElement_KeyUp;
                }
                _uiElement = value;
                _uiElement.KeyDown += _uiElement_KeyDown;
                _uiElement.KeyUp += _uiElement_KeyUp;
            }
        }

        private void _uiElement_KeyUp(object sender, System.Windows.Input.KeyEventArgs e)
        {
            KeyUp(e.Key);
        }

        private void _uiElement_KeyDown(object sender, System.Windows.Input.KeyEventArgs e)
        {
            KeyDown(e.Key);
        }

        public IKeyState AddState(IKeyState state)
        {
            _keyStates.Add(state);
            return state;
        }

        public IKeyState AddState(Action activated, Action deactivated, params Key[] keys)
        {
            var keyState = new KeyState(keys)
            {
                Activated = activated,
                Deactivated = deactivated
            };
            return AddState(keyState);
        }

        internal void KeyDown(Key key)
        {
            if (!_pressedKeys.Contains(key))
            {
                _pressedKeys.Add(key);
            }

            UpdateKeyStates();

        }

        internal void KeyUp(Key key)
        {

            if (_pressedKeys.Contains(key))
            {
                _pressedKeys.Remove(key);
            }

            UpdateKeyStates();

        }

        private void UpdateKeyStates()
        {

            _keyStates
                .Where(s => !s.Keys.All(k => _pressedKeys.Contains(k)))
                .Where(s => s.IsActive)
                .ToList()
                .ForEach(s =>
                {
                    s.IsActive = false;
                    if (s.Deactivated != null)
                    {
                        s.Deactivated();
                    }
                });

            _keyStates
                .Where(s => s.Keys.All(k => _pressedKeys.Contains(k)))
                //.Where(s => !s.IsActive)
                .ToList()
                .ForEach(s =>
                {
                    s.IsActive = true;
                    if (s.Activated != null)
                    {
                        s.Activated();
                    }
                });

        }

    }
}
